package cn.wolfcode.service.impl;

import cn.wolfcode.domain.Permission;
import cn.wolfcode.mapper.PermissionMapper;
import cn.wolfcode.query.PageResult;
import cn.wolfcode.query.QueryObject;
import cn.wolfcode.service.IPermissionService;
import cn.wolfcode.util.RequiredPermission;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Service
public class PermissionServiceImpl implements IPermissionService {

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private ApplicationContext applicationContext;


    @Override
    public PageInfo<Permission> query(QueryObject qo) {

        PageHelper.startPage(qo.getCurrentPage(),qo.getPageSize());
        List<Permission> list = permissionMapper.queryForList(qo);
        return new PageInfo<>(list);
    }

    @Override
    public void reload() {
        //为了避免重新加载的时候不重复添加数据,而且也要保持原来的权限数据不能改变(因为连着中间表)
        //因此需要去查询原来的权限数据,因为只要查询出权限的表达式就可以判断可当前插入的数据做对比(权限表达式是唯一的)
        List<String> expressions = permissionMapper.selectAllExpression();

        //获取spring容器的贴了注解@controller的bean对象
        Map<String, Object> objectMap = applicationContext.getBeansWithAnnotation(Controller.class);
        //controller这个对象是个集合,需要获取这个集合中所有的value,即所有的controller对象
        Collection<Object> controllers = objectMap.values();
        //对controller对象进行遍历
        for (Object controller : controllers) {
            //要判断获取的controller这个类是否贴了shiro的注解:如果是cgclib代理类说明贴了shiro的注解
            if (!AopUtils.isCglibProxy(controller)){
                //如果不是代理类,说明没贴shiro注解,那么那些没贴shiro注解的方法都是可以访问的不需要权限
                //因此也没必要去执行下面的判断,直接跳过本次循环即可
                continue;
            }
            //通过controller获取其方法,通过反射获取字节码对象,再获取方法对象(这里获取其父类的方法目的是
            // 由于贴上shiro的注解,导致获取的controller对象是cglib的代理对象,这个代理对象的方法肯定是没有贴注解的
            // 但是其父类肯定有注解的,因此要获取其父类的方法)
            Method[] methods = controller.getClass().getSuperclass().getDeclaredMethods();
            for (Method method : methods) {
                //获取方法上贴了@RequiresPermissions注解的对象
                RequiresPermissions annotation = method.getAnnotation(RequiresPermissions.class);
                //判断这个对象是否存在
                if (annotation != null) {
                    //如果这个对象存在,则获取这个注解对象的'属性'(比较特殊)
                    String expression = annotation.value()[0];
                    String name = annotation.value()[1];
                    //判断重新加载的所有的权限表达式在数据库中是否已经存在
                    if ((expressions!=null && ! expressions.contains(expression))||expressions==null){
                        //然后将获取的name和expression添加到数据库中
                        Permission permission = new Permission();
                        permission.setName(name);
                        permission.setExpression(expression);
                        permissionMapper.insert(permission);
                    }
                }

            }
        }




    }

    @Override
    public List<String> selectByEmpId(Long id) {
        List<String> expressions = permissionMapper.selectByEmpId(id);
        return expressions;
    }


    @Override
    public void save(Permission permission) {
         permissionMapper.insert(permission);
    }

    @Override
    public void update(Permission permission) {
        permissionMapper.updateByPrimaryKey(permission);
    }

    @Override
    public void delete(Long id) {
        permissionMapper.deleteByPrimaryKey(id);
    }

    @Override
    public Permission get(Long id) {
        return permissionMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<Permission> listAll() {
        return permissionMapper.selectAll();
    }


}
